#include <wx/sstream.h>
#include <wx/filename.h>

#include "SessionConnection.h"
#include "MsnTransport.h"
#include "MsnConnection.h"
#include "MsnMessenger.h"

#include "md5.h"
#include "Util.h"

#include "MsnSession.h"
#include "MsnCommand.h"


SessionConnection::SessionConnection(MsnSession* ms, bool mode)
	: session(ms), passive(mode)
{
	serverType = _T("SB");

	session->SetConnection(this);
}

SessionConnection::~SessionConnection()
{
    //delete socket;
    DEBUG(_T("~SessionConnection"));

}

void SessionConnection::ConnectionOpened()
{
    if(passive){
        OutCommandANS ans;
        ans.SetPassport(userPassport);
        ans.SetTicket(ticket);
        ans.SetSessionID(sessionID);
        SendCommand(ans);
    }else{
        OutCommandSwitchUSR usr;
        usr.SetPassport(userPassport);
        usr.SetTicket(ticket);
        SendCommand(usr);
    }
}

void SessionConnection::ConnectionFailed()
{
	if(passive == false){
		DEBUG(_T("try to start a new session"));

		int tranID = session->GetMessenger()->StartSession();

		//TODO associate the ID with current session
	}
}


void SessionConnection::ConnectionClosed()
{
	session->OnConnectionClosed();
}

void SessionConnection::ConnectionBroken()
{
    session->OnConnectionClosed();
}

void SessionConnection::ProcessCommand(MsnCommandWrapper* cmdWrapper)
{
	wxString type = cmdWrapper->GetCommand()->GetType();

    if(type.IsSameAs(_T("USR")))            ProcessUSR(cmdWrapper);
    else if(type.IsSameAs(_T("CAL")))       ProcessCAL(cmdWrapper);
    else if(type.IsSameAs(_T("JOI")))       ProcessJOI(cmdWrapper);
    else if(type.IsSameAs(_T("IRO")))       ProcessIRO(cmdWrapper);
    else if(type.IsSameAs(_T("ANS")))       ProcessANS(cmdWrapper);
    else if(type.IsSameAs(_T("MSG")))       ProcessMSG(cmdWrapper);
	else if(type.IsSameAs(_T("ACK")))       ProcessACK(cmdWrapper);
	else if(type.IsSameAs(_T("NAK")))       ProcessNAK(cmdWrapper);
    else if(type.IsSameAs(_T("BYE")))       ProcessBYE(cmdWrapper);

    else{}	
}


void SessionConnection::ProcessUSR(MsnCommandWrapper* wrapper)
{
	std::vector<wxString> contactList = session->GetContactList();

	for(std::vector<wxString>::iterator it = contactList.begin();it != contactList.end(); ++it){	
		CallContact(*it);
	}
	
}

void SessionConnection::ProcessCAL(MsnCommandWrapper* wrapper)
{
    //wxString ring = msg.getString(0);
    //wxString clientID = msg.getString(1);
    //manager->SessionEstablished(this);

}

void SessionConnection::ProcessJOI(MsnCommandWrapper* wrapper)
{
	InCommandJOI* cmd = (InCommandJOI*) wrapper->GetCommand();

    wxString passport = cmd->GetPassport();
    wxString nickname = cmd->GetName();

    DEBUG(nickname + _T(" joined session"));

	session->OnContactJoined(passport);
}

void SessionConnection::ProcessIRO(MsnCommandWrapper* wrapper)
{
	InCommandIRO* cmd = (InCommandIRO*) wrapper->GetCommand();
    wxString passport = cmd->GetPassport();
    DEBUG(passport + _T(" IRO"));

	session->OnContactListed(passport);

}

void SessionConnection::ProcessANS(MsnCommandWrapper* wrapper)
{
    DEBUG(_T("contact list finished"));

	session->OnContactListed(wxEmptyString);
}

void SessionConnection::ProcessBYE(MsnCommandWrapper* wrapper)
{
	InCommandBYE* cmd = (InCommandBYE*) wrapper->GetCommand();

	session->OnContactLeft(cmd->GetPassport());

    ///todo
    //Close();
}


void SessionConnection::ProcessMSG(MsnCommandWrapper* wrapper)
{
	InCommandMSG* cmd = (InCommandMSG*) wrapper->GetCommand();

   	wxMemoryBuffer& buf = wrapper->GetPayloadBuffer();

	//the message need be deleted
	MsnMessage* message = MsnMessageFactory::Get().ParseMessage((char*)buf.GetData(), buf.GetDataLen());

    if(message == NULL) return;

    message->SetContact(cmd->GetPassport());
    message->SetSession(this);

	//wxString db = message->ToString();
    DEBUG(_T("\r\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r\n") 
				+ message->ToString() + 
		  _T("\r\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r\n"));

	if(message->IsKindOf(CLASSINFO(ControlMessage))){

		session->OnControlMessageReceived((ControlMessage*)message);

	}else if(message->IsKindOf(CLASSINFO(InstantMessage))){

		session->OnInstantMessageReceived((InstantMessage*)message);

	}else if(message->IsKindOf(CLASSINFO(InviteMessage))){

		//session->OnInvitationMessageReceived((InviteMessage*)message);

	}else if(message->IsKindOf(CLASSINFO(P2PMessage))){
		
		session->OnP2PMessageReceived((P2PMessage*)message);

	}

	delete message;
}

void SessionConnection::ProcessACK(MsnCommandWrapper* wrapper)
{
	session->OnACKReceived(wrapper->GetCommand()->GetTransactionID()); 
}

void SessionConnection::ProcessNAK(MsnCommandWrapper* wrapper)
{
	session->OnNAKReceived(wrapper->GetCommand()->GetTransactionID()); 
}

void SessionConnection::SendMessage(MsnMessage& msg)
{
	wxMemoryBuffer msgBuf;
	msg.Encode(msgBuf);

	OutCommandMSG cmd;
    cmd.SetAckType(msg.GetAckType());   	
	cmd.SetLength(msgBuf.GetDataLen());

	wxMemoryBuffer cmdBuf;
	cmd.ToBuffer(cmdBuf);
	cmdBuf.AppendData(msgBuf.GetData(), msgBuf.GetDataLen());
 
	//DEBUG(msg.ToString());
	DEBUG(_T("\r\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n") 
			+ msg.ToString() +
		  _T("\r\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n"));

	transport->SendData(cmdBuf.GetData(), cmdBuf.GetDataLen());	

}

void SessionConnection::SendMessage(MsnMessage& msg, int& transID)
{
	wxMemoryBuffer msgBuf;
	msg.Encode(msgBuf);

	OutCommandMSG cmd;
    cmd.SetAckType(msg.GetAckType());   	
	cmd.SetLength(msgBuf.GetDataLen());

	transID = cmd.GetTransactionID();

	wxMemoryBuffer cmdBuf;
	cmd.ToBuffer(cmdBuf);
	cmdBuf.AppendData(msgBuf.GetData(), msgBuf.GetDataLen());
 
	//DEBUG(msg.ToString());
	DEBUG(_T("\r\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n") 
			+ msg.ToString() +
		  _T("\r\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n"));

	transport->SendData(cmdBuf.GetData(), cmdBuf.GetDataLen());	
}


void SessionConnection::CallContact(const wxString& contact)
{
	OutCommandCAL cal;
    cal.SetPassport(contact);
    SendCommand(cal);	
}
